package com.itheima.health.security;

import com.alibaba.fastjson.JSON;
import com.itheima.health.entity.Result;
import com.itheima.health.pojo.Permission;
import com.itheima.health.pojo.Role;
import com.itheima.health.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author ：石破天
 * @date ：Created in 2022/6/3
 * @description ：
 * @version: 1.0
 */
@Slf4j
@WebFilter(urlPatterns = "/*")
public class HealthSecurityFilter implements Filter {
    //定义请求白名单,这些请求经过过滤器直接放行
    private String[] auth = new String[]{
            "/user/login",
            "/user/logout",
            "/mobile/**"
    };
    //定义一个map集合,存放不同请求对应的权限要求,在应用启动时初始化数据
    private Map<String,String> reqPermission = new HashMap<>();

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
	    //初始化时,将路径及对应权限令牌放入map集合
        initReqPermission();
	}




    @Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
						 FilterChain filterChain) throws IOException, ServletException {
		//拦截所有请求
		HttpServletRequest request = (HttpServletRequest)servletRequest;
		HttpServletResponse response = (HttpServletResponse)servletResponse;
		// 1.获取URI
		String uri = request.getRequestURI();
		log.info("[权限检查过滤器...],当前uri:{}",uri);
		//2.判单当前请求uri是否在白名单中,存在,直接放行
        boolean result = isExistAuth(uri,auth);
        if (result){
            log.info("[权限检查过滤器...],当前uri:{},属于白名单,直接放行",uri);
            filterChain.doFilter(request,response);
            return;
        }
        //3.判断是否登录
        if (request.getSession().getAttribute("user")==null){//未登陆了,告诉前端
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(JSON.toJSONString(new Result(false,"用户未登录...")));
            return;
        }
        //登陆了
        //判断当前uri是否需要登录权限,不需要直接放行
        boolean b = isExistAuth(uri,reqPermission);
        if (!b){//不包含,直接放行
            log.info("[权限检查过滤器...],当前uri:{},不需要访问权限,直接放行",uri);
            filterChain.doFilter(request,response);
            return;
        }
        //包含,需要验证用户访问权限,获取用户信息
        User user =(User) request.getSession().getAttribute("user");
        //获取路径对应的权限令牌
        String s= null;
        if (uri.contains("/report")||uri.contains("/ordersetting")){
             s = reqPermission.get(uri.substring(0,uri.lastIndexOf("/"))+"/**");
        }else {
             s = reqPermission.get(uri);
        }
        //调用验证方法
        boolean havePermission = isHavePermission(s, user);
        if (havePermission){
            log.info("[权限检查过滤器...],用户{},拥有访问权直接放行",user.getUsername());
            filterChain.doFilter(request,response);
            return;
        }
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(JSON.toJSONString(new Result(false,"您暂无访问权限,请联系管理员添加...")));

    }

    //定义一个方法,判断请求路径是否存在于白名单中
    public boolean isExistAuth(String uri,Object a){
        AntPathMatcher pathMatcher = new AntPathMatcher();
        //遍历白名单数组
        if (a instanceof String[]){
            String[] auth = (String[]) a;
            for (String authUri : auth) {
                boolean result = pathMatcher.match(authUri, uri);
                if (result){
                    //请求路径属于请求白名单
                    return true;
                }
            }
        }
        //遍历权限集合
        if (a instanceof Map){
            Map<String,String> auth =(Map<String, String>) a;
            Set<Map.Entry<String, String>> entries = auth.entrySet();
            for (Map.Entry<String, String> entry : entries) {
                boolean result = pathMatcher.match(entry.getKey(), uri);
                if (result){
                    //请求路径需要访问权限
                    return true;
                }
            }
        }

        //请求路径不属于给定数组或集合
        return false;
    }

    //定义一个方法,判断登录用户有无权限
    public boolean isHavePermission(String keyword, User user){
        //获取到该登录用户的所有对应角色
        Set<Role> roles = user.getRoles();
        //遍历角色集合
        for (Role role : roles) {
            //获取单个角色对应的权限令牌集合
            Set<Permission> permissions = role.getPermissions();
            //遍历权限令牌集合,和传入权限令牌进行比对
            for (Permission permission : permissions) {
                if (keyword.equals(permission.getKeyword())){
                    //相匹配.返回true
                    return true;
                }
            }
        }
        //没有匹配的,返回false
        return false;
    }


	@Override
	public void destroy() {

	}
    private void initReqPermission() {
        reqPermission.put("/checkitem/add","CHECKITEM_ADD");
        reqPermission.put("/checkitem/deleteById","CHECKITEM_DELETE");
        reqPermission.put("/checkitem/edit","CHECKITEM_EDIT");
       // reqPermission.put("/checkitem/findPage","CHECKITEM_QUERY");
        reqPermission.put("/checkgroup/add","CHECKGROUP_ADD");
        reqPermission.put("/checkgroup/deleteById","CHECKGROUP_DELETE");
        reqPermission.put("/checkgroup/edit","CHECKGROUP_EDIT");
      //  reqPermission.put("/checkgroup/findPage","CHECKGROUP_QUERY");
        reqPermission.put("/setmeal/add","SETMEAL_ADD");
        reqPermission.put("/setmeal/deleteById","SETMEAL_DELETE");
        reqPermission.put("/setmeal/edit","SETMEAL_EDIT");
      //  reqPermission.put("/setmeal/findPage","SETMEAL_QUERY");
        reqPermission.put("/ordersetting/**","ORDERSETTING");
        reqPermission.put("/report/**","REPORT_VIEW");
        reqPermission.put("/menu/add","MENU_ADD");
        reqPermission.put("/menu/delete","MENU_DELETE");
        reqPermission.put("/menu/edit","MENU_EDIT");
        reqPermission.put("/menu/findPage","MENU_QUERY");
        reqPermission.put("/user/add","USER_ADD");
        reqPermission.put("/user/delete","USER_DELETE");
        reqPermission.put("/user/edit","USER_EDIT");
        reqPermission.put("/user/findPage","USER_QUERY");
    }

}